package service

import (
	"container/heap"
	"context"
	"errors"
	"log"
	"match-server/pvp/dto"
	"sync"
	"sync/atomic"
	"time"
)

// 常见错误定义
var (
	// ErrMatchQueueFull 表示匹配队列已满
	ErrMatchQueueFull = errors.New("match queue is full, please try again later")
	// ErrCancelFailed 表示取消匹配失败
	ErrCancelFailed = errors.New("failed to cancel match, try again later")
	// ErrServiceStopped 表示服务已停止
	ErrServiceStopped = errors.New("match service has been stopped")
)

// DefaultMatchService 实现匹配服务功能
type DefaultMatchService struct {
	matchQueue      *MatcherPriorityQueue        // 匹配者优先级队列
	matchCh         chan dto.Matcher             // 接收匹配请求的通道
	cancelCh        chan int                     // 接收取消请求的通道
	resultCh        chan *matchResultPair        // 内部匹配结果通道
	matchResults    map[int]chan dto.MatchResult // 按匹配者ID存储结果通道的映射
	shutdown        chan struct{}                // 用于协调关闭的通道
	stopped         bool                         // 表示服务是否已停止的标志
	mu              sync.RWMutex                 // 用于保护共享状态的互斥锁
	queueMu         sync.Mutex                   // 专用于保护队列操作的互斥锁
	matchInProgress atomic.Bool                  // 标记匹配过程是否正在进行
}

// matchResultPair 保存一对匹配者的匹配结果
type matchResultPair struct {
	matcher1 dto.Matcher
	matcher2 dto.Matcher
	result   dto.MatchResult
}

// NewDefaultMatchService 创建DefaultMatchService的新实例
func NewDefaultMatchService() *DefaultMatchService {
	s := &DefaultMatchService{
		matchQueue:   NewMatcherPriorityQueue(),
		matchCh:      make(chan dto.Matcher, 20),      // 增大缓冲区大小
		cancelCh:     make(chan int, 10),              // 添加缓冲区
		resultCh:     make(chan *matchResultPair, 10), // 添加结果通道
		matchResults: make(map[int]chan dto.MatchResult),
		shutdown:     make(chan struct{}),
	}
	return s
}

// Start 启动匹配服务
func (s *DefaultMatchService) Start(ctx context.Context) error {
	s.mu.Lock()
	if s.stopped {
		s.mu.Unlock()
		return ErrServiceStopped
	}
	s.mu.Unlock()

	go s.run(ctx)
	go s.processResults() // 在单独的goroutine中运行结果处理器

	return nil
}

// Stop 优雅地关闭匹配服务
func (s *DefaultMatchService) Stop() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	if s.stopped {
		return nil // 已经停止
	}

	s.stopped = true
	close(s.shutdown)

	// 清理并关闭所有等待中的结果通道
	for id, ch := range s.matchResults {
		ch <- dto.MatchResult{Success: false}
		close(ch)
		delete(s.matchResults, id)
	}

	return nil
}

// AddMatcher 将匹配者添加到队列
func (s *DefaultMatchService) AddMatcher(ctx context.Context, p dto.Matcher) (<-chan dto.MatchResult, error) {
	s.mu.RLock()
	if s.stopped {
		s.mu.RUnlock()
		return nil, ErrServiceStopped
	}
	s.mu.RUnlock()

	// 创建带缓冲的结果通道
	resultCh := make(chan dto.MatchResult, 1)

	// 存储结果通道
	s.mu.Lock()
	s.matchResults[p.GetMatcherId()] = resultCh
	s.mu.Unlock()

	// 尝试以非阻塞方式发送匹配请求
	select {
	case s.matchCh <- p:
		return resultCh, nil
	case <-ctx.Done():
		s.mu.Lock()
		delete(s.matchResults, p.GetMatcherId())
		s.mu.Unlock()
		return nil, ctx.Err()
	case <-s.shutdown:
		s.mu.Lock()
		delete(s.matchResults, p.GetMatcherId())
		s.mu.Unlock()
		return nil, ErrServiceStopped
	default:
		// 队列已满，清理并返回错误
		s.mu.Lock()
		delete(s.matchResults, p.GetMatcherId())
		s.mu.Unlock()
		return nil, ErrMatchQueueFull
	}
}

// CancelMatch 从队列中移除匹配者
func (s *DefaultMatchService) CancelMatch(matcherId int) error {
	s.mu.RLock()
	if s.stopped {
		s.mu.RUnlock()
		return ErrServiceStopped
	}
	s.mu.RUnlock()

	// 尝试带超时发送取消请求
	select {
	case s.cancelCh <- matcherId:
		s.mu.Lock()
		if ch, ok := s.matchResults[matcherId]; ok {
			close(ch)
			delete(s.matchResults, matcherId)
		}
		s.mu.Unlock()
		return nil
	case <-time.After(500 * time.Millisecond):
		return ErrCancelFailed
	case <-s.shutdown:
		return ErrServiceStopped
	}
}

// run 处理主服务循环
func (s *DefaultMatchService) run(ctx context.Context) {
	ticker := time.NewTicker(100 * time.Millisecond)
	defer ticker.Stop()

	for {
		select {
		case <-ctx.Done():
			s.Stop()
			return
		case <-s.shutdown:
			return
		case p := <-s.matchCh:
			s.queueMu.Lock()
			heap.Push(s.matchQueue, &p)
			s.queueMu.Unlock()
		case id := <-s.cancelCh:
			s.removeFromQueue(id)
		case <-ticker.C:
			// 仅当没有正在进行的匹配过程时才启动新的匹配
			if s.matchInProgress.CompareAndSwap(false, true) {
				go func() {
					s.tryMatch()
					// 匹配完成后重置标志
					s.matchInProgress.Store(false)
				}()
			} else {
				log.Println("上一次匹配尚未完成，跳过本次匹配")
			}
		}
	}
}

// processResults 在单独的goroutine中处理发送匹配结果
func (s *DefaultMatchService) processResults() {
	for {
		select {
		case <-s.shutdown:
			return
		case pair := <-s.resultCh:
			s.sendMatchResult(pair.matcher1, pair.matcher2, pair.result)
		}
	}
}

// tryMatch 尝试匹配队列中的玩家
func (s *DefaultMatchService) tryMatch() {
	// 获取队列锁，确保并发安全
	s.queueMu.Lock()

	if s.matchQueue.Len() < 2 {
		s.queueMu.Unlock()
		return
	}

	// 存储原始玩家以避免丢失
	players := make([]*dto.Matcher, 0, s.matchQueue.Len())

	// 首先，从队列中收集所有玩家
	for s.matchQueue.Len() > 0 {
		players = append(players, heap.Pop(s.matchQueue).(*dto.Matcher))
	}

	// 在收集完玩家后释放队列锁，允许新玩家加入队列
	s.queueMu.Unlock()

	// 仅使用一个映射来跟踪已匹配的玩家ID
	matchedIds := make(map[int]bool)

	// 使用简化的匹配算法
	for i := 0; i < len(players); i++ {
		// 获取玩家ID并检查是否已匹配
		player1Id := (*players[i]).GetMatcherId()

		// 跳过已匹配的玩家
		if matchedIds[player1Id] {
			continue
		}

		// 寻找第一个可匹配的玩家
		for j := i + 1; j < len(players); j++ {
			// 获取候选匹配玩家ID
			player2Id := (*players[j]).GetMatcherId()

			// 跳过已匹配的玩家
			if matchedIds[player2Id] {
				continue
			}

			// 自己不跟自己匹配
			if player1Id == player2Id {
				continue
			}

			// 检查这些玩家是否可以匹配
			if s.isValidMatch(*players[i], *players[j]) {
				// 找到有效匹配，记录两个玩家ID已被匹配
				matchedIds[player1Id] = true
				matchedIds[player2Id] = true

				// 创建匹配结果
				result := dto.MatchResult{
					Matcher1: *players[i],
					Matcher2: *players[j],
					Success:  true,
				}

				log.Printf("匹配成功: 玩家%d(分数:%d) 与 玩家%d(分数:%d), 分数差:%d",
					player1Id, (*players[i]).GetScore(),
					player2Id, (*players[j]).GetScore(),
					abs((*players[i]).GetScore()-(*players[j]).GetScore()))

				// 发送到结果通道进行处理（非阻塞）
				select {
				case s.resultCh <- &matchResultPair{
					matcher1: *players[i],
					matcher2: *players[j],
					result:   result,
				}:
					// 成功发送
				default:
					// 结果通道已满，取消匹配标记
					matchedIds[player1Id] = false
					matchedIds[player2Id] = false
				}

				// 找到匹配后跳出内层循环
				break
			}
		}
	}

	// 将未匹配的玩家返回队列
	s.queueMu.Lock()
	for _, player := range players {
		playerId := (*player).GetMatcherId()
		if !matchedIds[playerId] {
			heap.Push(s.matchQueue, player)
		}
	}
	s.queueMu.Unlock()
}

// isValidMatch 检查两个匹配者是否可以匹配在一起
func (s *DefaultMatchService) isValidMatch(p1, p2 dto.Matcher) bool {
	// 首先检查他们是否有相同的匹配类型
	if p1.GetMatchType() != p2.GetMatchType() {
		return false
	}

	// 计算分数差异
	scoreDiff := abs(p1.GetScore() - p2.GetScore())

	// 计算等待时间 - 使用等待时间较长的玩家
	waitTime1 := time.Since(p1.GetStartMatchTime())
	waitTime2 := time.Since(p2.GetStartMatchTime())
	waitTime := waitTime1
	if waitTime2 > waitTime1 {
		waitTime = waitTime2
	}

	// 根据等待时间动态调整可接受的分数差异
	// 等待时间越长，我们就越放宽匹配标准
	maxScoreDiff := 100 + int(waitTime.Minutes())*50

	return scoreDiff <= maxScoreDiff
}

// sendMatchResult 向两名玩家发送匹配结果
func (s *DefaultMatchService) sendMatchResult(p1, p2 dto.Matcher, result dto.MatchResult) {
	s.mu.Lock()
	defer s.mu.Unlock()

	// 如果通道存在，发送给第一个匹配者
	if ch1, ok := s.matchResults[p1.GetMatcherId()]; ok {
		select {
		case ch1 <- result:
			// 发送成功
		default:
			// 通道已满或已关闭，跳过
		}
		close(ch1)
		delete(s.matchResults, p1.GetMatcherId())
	}

	// 如果通道存在，发送给第二个匹配者
	if ch2, ok := s.matchResults[p2.GetMatcherId()]; ok {
		select {
		case ch2 <- result:
			// 发送成功
		default:
			// 通道已满或已关闭，跳过
		}
		close(ch2)
		delete(s.matchResults, p2.GetMatcherId())
	}
}

// removeFromQueue 通过ID从队列中移除匹配者
func (s *DefaultMatchService) removeFromQueue(matcherId int) {
	s.queueMu.Lock()
	defer s.queueMu.Unlock()

	// 使用切片实现更高效的方法
	tempSlice := make([]*dto.Matcher, 0, s.matchQueue.Len())

	// 将所有匹配者提取到切片中，过滤掉要移除的匹配者
	for s.matchQueue.Len() > 0 {
		p := heap.Pop(s.matchQueue).(*dto.Matcher)
		if (*p).GetMatcherId() != matcherId {
			tempSlice = append(tempSlice, p)
		}
	}

	// 将所有剩余匹配者放回队列
	for _, p := range tempSlice {
		heap.Push(s.matchQueue, p)
	}
}

// MatcherPriorityQueue 实现匹配者的优先级队列
type MatcherPriorityQueue []*dto.Matcher

// Len 返回队列长度
func (pq MatcherPriorityQueue) Len() int { return len(pq) }

// Less 比较两个匹配者的开始时间 - 较早的时间具有更高的优先级
func (pq MatcherPriorityQueue) Less(i, j int) bool {
	return (*pq[i]).GetStartMatchTime().Before((*pq[j]).GetStartMatchTime())
}

// Swap 交换队列中的两个匹配者
func (pq MatcherPriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

// Push 将匹配者添加到队列
func (pq *MatcherPriorityQueue) Push(x interface{}) {
	item := x.(*dto.Matcher)
	*pq = append(*pq, item)
}

// Pop 移除并返回最高优先级的匹配者
func (pq *MatcherPriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

// NewMatcherPriorityQueue 创建一个新的匹配者优先级队列
func NewMatcherPriorityQueue() *MatcherPriorityQueue {
	pq := &MatcherPriorityQueue{}
	heap.Init(pq)
	return pq
}

// abs 返回整数的绝对值
func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}
